package com.wordplat.quickstart.xutils;

import com.wordplat.quickstart.xutils.common.util.KeyValue;
import com.wordplat.quickstart.xutils.common.util.TextUtils;
import com.wordplat.quickstart.xutils.db.Selector;
import com.wordplat.quickstart.xutils.db.sqlite.SqlInfo;
import com.wordplat.quickstart.xutils.db.sqlite.WhereBuilder;
import com.wordplat.quickstart.xutils.db.table.DbModel;
import com.wordplat.quickstart.xutils.db.table.TableEntity;
import com.wordplat.quickstart.xutils.ex.DbException;

import ohos.data.rdb.RdbStore;
import ohos.data.resultset.ResultSet;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * 数据库访问接口
 *
 * @since 2021-05-09
 */
public interface DbManager extends Closeable {
    /**
     * getDaoConfig
     *
     * @return DaoConfig
     */
    DaoConfig getDaoConfig();

    /**
     * getDatabase
     *
     * @return RdbStore
     */
    RdbStore getDatabase();

    /**
     * saveBindingId
     *
     * @param entity
     * @return boolean
     * @throws DbException
     */
    boolean saveBindingId(Object entity) throws DbException;

    /**
     * saveOrUpdate
     *
     * @param entity
     * @throws DbException
     */
    void saveOrUpdate(Object entity) throws DbException;

    /**
     * save
     *
     * @param entity
     * @throws DbException
     */
    void save(Object entity) throws DbException;

    /**
     * replace
     *
     * @param entity
     * @throws DbException
     */
    void replace(Object entity) throws DbException;

    /**
     * deleteById
     *
     * @param entityType
     * @param idValue
     * @throws DbException
     */
    void deleteById(Class<?> entityType, Object idValue) throws DbException;

    /**
     * delete
     *
     * @param entity
     * @throws DbException
     */
    void delete(Object entity) throws DbException;

    /**
     * delete
     *
     * @param entityType
     * @throws DbException
     */
    void delete(Class<?> entityType) throws DbException;

    /**
     * delete
     *
     * @param entityType
     * @param whereBuilder
     * @return int
     * @throws DbException
     */
    int delete(Class<?> entityType, WhereBuilder whereBuilder) throws DbException;

    /**
     * update
     *
     * @param entity
     * @param updateColumnNames
     * @throws DbException
     */
    void update(Object entity, String... updateColumnNames) throws DbException;

    /**
     * update
     *
     * @param entityType
     * @param whereBuilder
     * @param nameValuePairs
     * @return update
     * @throws DbException
     */
    int update(Class<?> entityType, WhereBuilder whereBuilder, KeyValue... nameValuePairs) throws DbException;

    /**
     * findById
     *
     * @param entityType
     * @param idValue
     * @param <T>
     * @return T
     * @throws DbException
     */
    <T> T findById(Class<T> entityType, Object idValue) throws DbException;

    /**
     * findFirst
     *
     * @param entityType
     * @param <T>
     * @return T
     * @throws DbException
     */
    <T> T findFirst(Class<T> entityType) throws DbException;

    /**
     * findAll
     *
     * @param entityType
     * @param <T>
     * @return List
     * @throws DbException
     */
    <T> List<T> findAll(Class<T> entityType) throws DbException;

    /**
     * selector
     *
     * @param entityType
     * @param <T>
     * @return Selector
     * @throws DbException
     */
    <T> Selector<T> selector(Class<T> entityType) throws DbException;

    /**
     * findDbModelFirst
     *
     * @param sqlInfo
     * @return DbModel
     * @throws DbException
     */
    DbModel findDbModelFirst(SqlInfo sqlInfo) throws DbException;

    /**
     * findDbModelAll
     *
     * @param sqlInfo
     * @return List
     * @throws DbException
     */
    List<DbModel> findDbModelAll(SqlInfo sqlInfo) throws DbException;

    /**
     * getTable
     *
     * @param entityType
     * @param <T>
     * @return T
     * @throws DbException
     */
    <T> TableEntity<T> getTable(Class<T> entityType) throws DbException;

    /**
     * dropTable
     *
     * @param entityType
     * @throws DbException
     */
    void dropTable(Class<?> entityType) throws DbException;

    /**
     * addColumn
     *
     * @param entityType
     * @param column
     * @throws DbException
     */
    void addColumn(Class<?> entityType, String column) throws DbException;
    /**
     * dropDb
     *
     * @throws DbException
     */
    void dropDb() throws DbException;
    /**
     * close
     *
     * @throws IOException
     */
    void close() throws IOException;

    /**
     * executeUpdateDelete
     *
     * @param sqlInfo
     * @return int
     * @throws DbException
     */
    int executeUpdateDelete(SqlInfo sqlInfo) throws DbException;

    /**
     * executeUpdateDelete
     *
     * @param sql
     * @return int
     * @throws DbException
     */
    int executeUpdateDelete(String sql) throws DbException;

    /**
     * execNonQuery
     *
     * @param sqlInfo
     * @throws DbException
     */
    void execNonQuery(SqlInfo sqlInfo) throws DbException;

    /**
     * execNonQuery
     *
     * @param sql
     * @throws DbException
     */
    void execNonQuery(String sql) throws DbException;

    /**
     * execQuery
     *
     * @param sqlInfo
     * @return ResultSet
     * @throws DbException
     */
    ResultSet execQuery(SqlInfo sqlInfo) throws DbException;

    /**
     * execQuery
     *
     * @param sql
     * @return ResultSet
     * @throws DbException
     */
    ResultSet execQuery(String sql) throws DbException;

    /**
     * DbOpenListener
     *
     * @since 2021-05-09
     */
    interface DbOpenListener {
        /**
         * onDbOpened
         *
         * @param db
         * @throws DbException
         */
        void onDbOpened(DbManager db) throws DbException;
    }

    /**
     * DbUpgradeListener
     *
     * @since 2021-05-09
     */
    interface DbUpgradeListener {
        /**
         * onUpgrade
         *
         * @param db
         * @param oldVersion
         * @param newVersion
         * @throws DbException
         */
        void onUpgrade(DbManager db, int oldVersion, int newVersion) throws DbException;
    }

    /**
     * TableCreateListener
     *
     * @since 2021-05-09
     */
    interface TableCreateListener {
        /**
         * onTableCreated
         *
         * @param db
         * @param table
         */
        void onTableCreated(DbManager db, TableEntity<?> table);
    }

    /**
     * DbOpenListener
     *
     * @since 2021-05-09
     */
    class DaoConfig {
        private File dbDir;
        private String dbName = "xUtils.db"; // default db name
        private int dbVersion = 1;
        private boolean allowTransaction = true;
        private DbUpgradeListener dbUpgradeListener;
        private TableCreateListener tableCreateListener;
        private DbOpenListener dbOpenListener;

        /**
         * DaoConfig
         */
        public DaoConfig() {
        }

        /***
         * DaoConfig
         *
         * @param dbDir
         * @return DaoConfig
         */
        public DaoConfig setDbDir(File dbDir) {
            this.dbDir = dbDir;
            return this;
        }

        /**
         * setDbName
         *
         * @param dbName
         * @return DaoConfig
         */
        public DaoConfig setDbName(String dbName) {
            if (!TextUtils.isEmpty(dbName)) {
                this.dbName = dbName;
            }
            return this;
        }

        /**
         * setDbVersion
         *
         * @param dbVersion
         * @return DaoConfig
         */
        public DaoConfig setDbVersion(int dbVersion) {
            this.dbVersion = dbVersion;
            return this;
        }

        /**
         * setAllowTransaction
         *
         * @param allowTransaction
         * @return DaoConfig
         */
        public DaoConfig setAllowTransaction(boolean allowTransaction) {
            this.allowTransaction = allowTransaction;
            return this;
        }

        /**
         * setDbOpenListener
         *
         * @param dbOpenListener
         * @return DaoConfig
         */
        public DaoConfig setDbOpenListener(DbOpenListener dbOpenListener) {
            this.dbOpenListener = dbOpenListener;
            return this;
        }

        /**
         * setDbUpgradeListener
         *
         * @param dbUpgradeListener
         * @return DaoConfig
         */
        public DaoConfig setDbUpgradeListener(DbUpgradeListener dbUpgradeListener) {
            this.dbUpgradeListener = dbUpgradeListener;
            return this;
        }

        /**
         * setTableCreateListener
         *
         * @param tableCreateListener
         * @return DaoConfig
         */
        public DaoConfig setTableCreateListener(TableCreateListener tableCreateListener) {
            this.tableCreateListener = tableCreateListener;
            return this;
        }

        public File getDbDir() {
            return dbDir;
        }

        public String getDbName() {
            return dbName;
        }

        public int getDbVersion() {
            return dbVersion;
        }

        public boolean isAllowTransaction() {
            return allowTransaction;
        }

        public DbOpenListener getDbOpenListener() {
            return dbOpenListener;
        }

        public DbUpgradeListener getDbUpgradeListener() {
            return dbUpgradeListener;
        }

        public TableCreateListener getTableCreateListener() {
            return tableCreateListener;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            DaoConfig daoConfig = (DaoConfig) o;

            if (!dbName.equals(daoConfig.dbName)) {
                return false;
            }
            return dbDir == null ? daoConfig.dbDir == null : dbDir.equals(daoConfig.dbDir);
        }

        @Override
        public int hashCode() {
            int result = dbName.hashCode();
            result = 31 * result + (dbDir != null ? dbDir.hashCode() : 0);
            return result;
        }

        @Override
        public String toString() {
            return dbDir + "/" + dbName;
        }
    }
}
